#!/usr/bin/python
import time
from htmlgen import HTMLgen

#Data with known Representation

def getScript():
    result = \
"""
function switchUL(element) {
    var parent = element.parentNode;
    for (i = 0; i < element.parentNode.childNodes.length; ++i) {
        if (parent.childNodes[i].nodeName.toLowerCase() == "ul") {
            var ul = parent.childNodes[i];
            if (ul.style.display != 'none') {
                ul.style.display = 'none';
                parent.parentNode.style.listStyleType = 'circle';
            } else {
                ul.style.display = 'block';
                parent.parentNode.style.listStyleType = 'disc';
            }
        }
    }
}

function SwapTr(tableName, index1)
{
    var tabl = document.getElementById(tableName);
    tabl.rows[0].parentNode.insertBefore(tabl.rows[index1 + 1], tabl.rows[index1]);
}

function compareText(text1, text2, desc)
{
    if (desc) {
        if (text1.toLowerCase() > text2.toLowerCase()) {
            return 1;
        }
        if (text2.toLowerCase() > text1.toLowerCase()) {
            return -1;
        }
    } else {
        if (text1.toLowerCase() < text2.toLowerCase()) {
            return 1;
        }
        if (text2.toLowerCase() < text1.toLowerCase()) {
            return -1;
        }
    }
    return 0;
}

function SortRows(tableName, desc, rowClass)
{
    var table = document.getElementById(tableName);

    for (i = 2; i < table.rows.length; ++i) {
        for (j = i - 1; j > 0; --j) {
            var prev = table.rows[j].getElementsByClassName(rowClass)[0];
            var curr = table.rows[j + 1].getElementsByClassName(rowClass)[0];
            if (compareText(prev.innerHTML, curr.innerHTML, desc) == 1) {
                SwapTr(tableName, j);
            } else {
                break;
            }
        }
    }
}

function onTHclick(name, th) {
    var e = document.getElementsByClassName(name);
    var display = true;
    for (var i=0, len=e.length; i<len; ++i){
            if(e[i].style.display != 'none') {
                e[i].style.display = 'none';
                display = false;
            } else {
                e[i].style.display = 'block';
                display = true;
            }
    }
    var th_div = document.getElementById(th);
    if (display) {
        th_div.innerHTML= th_div.innerHTML.substring(0, th_div.innerHTML.length - 3) + "[-]";
    } else {
        th_div.innerHTML= th_div.innerHTML.substring(0, th_div.innerHTML.length - 3) + "[+]";
    }
}
setTimeout("location.reload(true);", 30000)
"""
    return result

def getStyle():
    result = \
"""
h1 {
    font: bold 24px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
}

h2 {
    font: bold 20px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
}

th {
    font: bolder 16px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
    color: black;
    border-right: 2px solid #C1DAD7;
    border-bottom: 2px solid #C1DAD7;
    border-top: 2px solid #C1DAD7;
    letter-spacing: 2px;
    text-transform: uppercase;
    text-align: left;
    padding: 6px 6px 6px 12px;
    background: #CAE8EA;
}

th span {
    text-decoration:none;
}

th span:hover {
   text-decoration:underline; 
}

td {
    border-right: 2px solid #C1DAD7;
    border-bottom: 2px solid #C1DAD7;
    padding: 6px 6px 6px 12px;
}

tr {
    font: 15px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
    background: #fff;
    color: black;
}

tr.Late {
    color:red;
}

tr.Start {
    background: lightgreen;
}

tr.LateStart {
    background: pink;
    color: black;
}

tr.Deleted {
    color: gray;
    text-decoration: line-through;
}

tr.Completed {
    color: green;
}

tr.LateCompleted {
    color: red;
}

ul {
    font: 15px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
    text-align: left;
    text-decoration:none;
}

ul span.normal {
    color:black;
    text-decoration:none;
}

ul span.normal:hover {
    text-decoration:underline;
}

ul span.Late {
    color:red;
}

ul span.Late:hover {
    text-decoration:underline;
}

ul span.Start {
    color:black;
    background: lightgreen;
}

ul span.Start:hover {
    text-decoration:underline;
}

ul span.LateStart {
    background: pink;
    color: black;
    text-decoration: none;
}

ul span.LateStart:hover {
    text-decoration:underline;
}

ul span.Deleted {
    color: gray;
    text-decoration: line-through;
}

ul span.Deleted:hover {
    text-decoration:underline;
}

ul span.Completed {
    color: green;
    text-decoration: line-through;
}

ul span.Completed:hover {
    text-decoration:underline;
}

ul span.LateCompleted {
    color: red;
    text-decoration: line-through;
}

ul span.LateCompleted:hover {
    text-decoration:underline;
}

"""
    return result

def reprDate(data):
    div = HTMLgen.Div()
    if (data != "") :
        div.append(time.strftime("%Y-%m-%d", time.gmtime(long(data))))
        div.append(HTMLgen.BR())
        div.append(time.strftime("%H:%M", time.gmtime(long(data))))
    return div

reprFunctions = { "due":reprDate, "entry":reprDate, "start":reprDate, "end":reprDate }
autoHide = { "parent", "uuid", "mask", "depends" }

def Repr(name, data):
    if name in reprFunctions:
        return reprFunctions[name](data)
    return data

#Returns names of the columns + count ["uuid":16, ... ]
def getColumnNamesCount(parsedList):
    result = {}
    for (parsedItem, clas) in parsedList:
        for element in parsedItem.keys():
            if element in result:
                result[element] = result[element] + 1
            else:
                result[element] = 1
    return result

#Sorts  ["uuid":16, "project":3] -> ["uuid", "project"]
def sortColumnNames(countDict):
    perNumber = {}
    for key in countDict.keys():

        if countDict[key] in perNumber.keys():
            perNumber[countDict[key]].append(key)
        else:
            perNumber[countDict[key]] = [key]

    result = []
    for key in reversed(sorted(perNumber.keys())):
        result = result + sorted(perNumber[key])

    return result

#Generate TD data
def generateTD(name, tabID, data, show=True):
    TD = HTMLgen.TD(align="center", valign="middle")
    DIV = HTMLgen.Div()
    DIV.attr_dict["class"] = ' class="TD_' + tabID + "_" + name + '"'
    DIV.attr_dict["style"] = ' style="display:block"' if show else ' style="display:none"'
    DIV.append(Repr(name, data))
    TD.append(DIV)
    return TD

#Generate TH data
def generateTH(name, tabID, show=True):
    if show:
        openclose = HTMLgen.Span("[-]")
    else:
        openclose = HTMLgen.Span("[+]")
    openclose.attr_dict["id"] = ' id="TH_' + tabID + "_" + name + '"'
    openclose.attr_dict["style"] = ' onclick="onTHclick(\'TD_' + tabID + "_" + name + '\', \'TH_'+ tabID + "_" + name + '\');"'
    DIV = HTMLgen.Div(name, openclose , align="left")
    desc = HTMLgen.Span("[dsc]")
    desc.attr_dict["style"] = ' onclick="SortRows(\'' + tabID + '\', true, \'TD_'+ tabID + "_" + name + '\');"'
    asc = HTMLgen.Span("[asc]")
    asc.attr_dict["style"] = ' onclick="SortRows(\'' + tabID + '\', false, \'TD_'+ tabID + "_" + name + '\');"'
    DIV2 = HTMLgen.Div(desc, asc, align="right")
    DIV2.attr_dict["class"] = ' class="TD_' + tabID + "_" + name + '"'
    DIV2.attr_dict["style"] = ' style="display:block"' if show else ' style="display:none"'
    TH = HTMLgen.TH(DIV, DIV2, align="center", valign="middle")
    return TH

def putAsFirst(lst, element):
    if element in lst:
        lst.remove(element)
    lst.insert(0, element)

def putAsLast(lst, element):
    if element in lst:
        lst.remove(element)
    lst.append(element)

def generateDependenciesUL(pending, completed, all=False):
    #Merge both lists
    data = pending + completed
    #Build dict acccordig to uuid
    uuidDict = {}
    #map(lambda x: uuidDict.update(map((x[0])["uuid"], x)), data)
    for line in data:
        uuidDict[line[0]["uuid"]] = line

    lst = []
    map(lambda x: lst.append(x[0]["uuid"]), data) 

    tree = []
    for line in data:
        if "depends" not in line[0]:
            lst.remove(line[0]["uuid"])
            tree.append((line[0]["uuid"], []))

    #Create a tree
    while lst:
        for line in lst:
            deps = uuidDict[line][0]["depends"].split(',')
            #put inisde tree only if both dependencies are not inside lst
            put = True
            for dep in deps:
                if dep in lst:
                    put = False
            if put:
                putItem = (line, [])
                for treeItem in tree:
                    if treeItem[0] in deps:
                        putItem[1].append(treeItem)
                tree.append(putItem)
                lst.remove(line)
                break

    if not all:
        #Filter Empty trees
        tree = filter(lambda x: 0 != len(x[1]), tree)

    if not all:
        #Remove dependent root trees
        filtered = set()
        for item in tree:
            stack = list(item[1])
            #print stack
            while stack:
                last = stack.pop()
                filtered.add(last[0])
                stack.extend(list(last[1]))
        tree = filter(lambda x: x[0] not in filtered, tree)

    htmlList = []
    #Walk the tree
    for item in tree:
        # stack [[item, depIndex, htmlTag], ...]
        stack = [ [item, 0, list()] ]
        while stack:
            #Print on first iteration
            #if stack[-1][1] == 0:
                #print " " * len(stack) + stack[-1][0][0]
            #Length of child nodes
            if stack[-1][1] == len(stack[-1][0][1]):
                htmlUl = HTMLgen.UL(stack[-1][2], style='list-style-type:disc;display:block;')
                htmlDiv = formatUlTag(stack[-1][0][0], uuidDict, htmlUl)
                if len(stack) == 1:
                    htmlList.append(htmlDiv)
                else:
                    stack[-2][2].append(htmlDiv)
                stack.pop()
            else:
                stack[-1][1] = stack[-1][1] + 1
                stack.append([stack[-1][0][1][stack[-1][1] - 1], 0, list()])
    result = HTMLgen.Div(HTMLgen.UL(htmlList, style='list-style-type:disc;display:block'))
    return result

def formatUlTag(uuid, uuidDict, htmlUl):
    strRes = HTMLgen.Span()
    item = uuidDict[uuid]
    if "ID" in item[0]:
        strRes.append(HTMLgen.Strong(str(item[0]["ID"])), ". ")
    else:
        if item[0]["status"] == "completed":
            strRes.prepend("[X] ") 
        elif item[0]["status"] == "deleted":
            strRes.prepend("[-] ") 
    strRes.append(item[0]["description"])
    strRes.attr_dict["id"] = ' onclick="switchUL(this);"'
    strRes.attr_dict["class"] = ' class="' + item[1] + '"'
    result = HTMLgen.Div(strRes, htmlUl)
    return result

#INPUT Json Formatted pending and completed Tasks
def generateTaskListFull(pending, completed, targetPath):
    document = HTMLgen.SimpleDocument(title = "Task List Full", style=getStyle())

    #Add the java script
    script = HTMLgen.Script(code=getScript())
    document.append(script)

    #Pending tasks
    document.append(HTMLgen.Heading(2, "Pending Tasks", align="center"))

    table = HTMLgen.TableLite(border=0, tabletitle="Pending Tasks", align="center", valign="middle")
    table.attr_dict["id"] = ' id="TablePending"'

    row = HTMLgen.TR()
    header = sortColumnNames(getColumnNamesCount(pending))
    putAsFirst(header, "ID")
    putAsLast(header, "uuid")
    map(lambda x: row.append(generateTH(x, "TablePending", x not in autoHide)), header)
    table.append(row)

    for (line, clas) in pending:
        row = HTMLgen.TR()
        row.attr_dict["class"] = ' class="' + clas + '"'
        map(lambda x: row.append(generateTD(x, "TablePending", line[x], x not in autoHide) if x in line else generateTD(x, "TablePending", "", x not in autoHide)), header)
        table.append(row)

    document.append(table)

    document.append(HTMLgen.Heading(2, "Dependencies", align="center"))
    UL = generateDependenciesUL(pending, completed)
    table = HTMLgen.TableLite(border=0, tabletitle="Dependencies", align="center", valign="middle")
    table.append(HTMLgen.TR(HTMLgen.TD(UL, style="border:none;")))
    document.append(table)
    
    #Completed tasks
    document.append(HTMLgen.Heading(2, "Completed Tasks", align="center"))
    table = HTMLgen.TableLite(border=0, tabletitle="Completed Tasks", align="center", valign="middle")
    table.attr_dict["id"] = ' id="TableCompleted"'

    row = HTMLgen.TR()
    header = sortColumnNames(getColumnNamesCount(completed))
    putAsLast(header, "uuid")
    map(lambda x: row.append(generateTH(x, "TableCompleted", x not in autoHide)), header)
    table.append(row)

    for (line, clas) in completed:
        row = HTMLgen.TR()
        row.attr_dict["class"] = ' class="' + clas + '"'
        map(lambda x: row.append(generateTD(x, "TableCompleted", line[x], x not in autoHide) if x in line else generateTD(x, "TableCompleted", "", x not in autoHide)), header)
        table.append(row)

    document.append(table)


    with open(targetPath, 'w') as f:
        f.write(str(document))
